/**
 *  Copyright (c) 2010 The edtf project.  All rights reserved.
 *
 *  This file is part of edtf (Event Driven Testing Framework).
 *
 *  edtf is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  edtf is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with edtf.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  This software consists of voluntary contributions made by many
 *  individuals.  For exact contribution history, see the revision
 *  history and logs, available at http://code.google.com/p/edtf.
 */
package org.edtf.engine.ws.service;

import org.edtf.engine.ws.jaxws.MessageIO;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import java.util.logging.XMLFormatter;
import javax.xml.ws.Endpoint;
import org.xepf.utils.Configuration;
import org.xepf.utils.ConfigurationLoader;
import org.xepf.utils.ObjectCreator;
import org.xepf.utils.FileUtils;
import org.xepf.utils.Sys;
import org.xepf.utils.Usage;
import org.xepf.eventboard.EventBoardManager;
import org.xepf.event.EventManager;
import org.xepf.script.ExecutionContext;
import org.xepf.script.ScriptPackage;

/**
 *
 * 
 */
public class Core {

    // todo: generate build information during build
    public static final String appName = "edtf.server";
    public static final String appVersion = "0.0.1";
    public static final String appReleaseDate = "2012-01-03";

    public static void main(String[] args) {

        Logger logger = Logger.getLogger("");
        System.out.println(Usage.getStartupBanner(appName, appVersion, appReleaseDate));

        if (!hasValidArguments(args)) {
            System.err.println(" An error was encountered while starting " + appName
                    + ": incorrect arguments were provided on the command line." + Sys.getProperty("line.separator"));
            showUsage();
            System.exit(-1);
        }

        String edtfServerConfigFile = args[0];
        String xtempTranslatorFile = args[1];
        String xtempScriptFile = args[2];
        String initialEventsFile = args[3];

//        String edtfServerConfigFile = "edtf.config.xml";
//        String xtempTranslatorFile = "src/org/edtf/engine/xtemp/translator/xtemp_translator.xsl";
//        String xtempScriptFile = "test/org/edtf/test/scripts/oasis/usecase-1.xtemp";
//        String initialEventsFile = "test/org/edtf/test/events/oasis/noevents.xml";

        Endpoint endpoint = null;
        EventBoardManager boardManager = null;
        EventManager eventManager = null;

        Configuration config = new Configuration();
        try {
            // load the XML configuration files:
            loadConfigFile(config, edtfServerConfigFile);
            String componentsXmlFile = config.getProperty("component.mapper-file");
            loadConfigFile(config, componentsXmlFile);

            // ObjectCreator needs the Config:
            ObjectCreator.setConfiguration(config);

            configureLogger(logger, config);

            // create the board and event managers
            boardManager = (EventBoardManager) ObjectCreator.get("EventBoardManager");
            eventManager = (EventManager) ObjectCreator.get("EventManager");
            eventManager.setEventBoardManager(boardManager);

            // prepare the service
            String serviceName = config.getProperty("service.name");
            String serviceIP = config.getProperty("service.ip");
            String servicePort = config.getProperty("service.port");
            MessageIO messageIO = (MessageIO) ObjectCreator.get("MessageIO");
            messageIO.setEventManager(eventManager);

            String serviceURL = "http://" + serviceIP + ":" + servicePort + "/" + serviceName;
            // the application name and version should always be present in the log
            Logger.getLogger(Core.class.getName()).info("Starting " + appName + " " + appVersion + " at " + serviceURL + " ..");
            
            endpoint = Endpoint.publish(serviceURL, messageIO);
        } catch (Exception ex) {
            Sys.showExceptionAndExit(ex);
        }

        ScriptPackage scriptPackage = null;

        try {
            String script = FileUtils.readFile(xtempScriptFile, (int) FileUtils.getFileSize(xtempScriptFile));
            String translator = FileUtils.readFile(xtempTranslatorFile, (int) FileUtils.getFileSize(xtempTranslatorFile));
            String events = FileUtils.readFile(initialEventsFile, (int) FileUtils.getFileSize(initialEventsFile));

            // prepare the execution context
            ExecutionContext executionContext = (ExecutionContext) ObjectCreator.get("ExecutionContext");
            executionContext.setConfiguration(config);
            executionContext.setScript(script);
            executionContext.setTranslator(translator);
            executionContext.setSampleEvents(events);
            executionContext.setEventBoardManager(boardManager);
            executionContext.setEventManager(eventManager);

            scriptPackage = (ScriptPackage) ObjectCreator.get("ScriptPackage");
            scriptPackage.initialize(executionContext);
            scriptPackage.run();

        } catch (Exception ex) {
            Sys.showExceptionAndExit(ex);
        }

        System.out.println(scriptPackage.getResult());
        System.exit(0);
    }

    private static boolean hasValidArguments(String[] args) {
        if (args.length == 4) {
            return true;
        }
        return false;
    }

    private static void loadConfigFile(Configuration configuration, String configFile) throws Exception {
        String configXml = FileUtils.readFile(configFile, (int) FileUtils.getFileSize(configFile));
        ConfigurationLoader configLoader = new ConfigurationLoader(configuration);
        configLoader.initialize(configXml);
    }

    private static void showUsage() {
        StringBuilder usage = new StringBuilder();
        String lineSeparator = Sys.getProperty("line.separator");
        usage.append("---------------------------------------" + lineSeparator);
        usage.append(" " + appName + " can be started using the following mandatory arguments:" + lineSeparator + lineSeparator);
        usage.append("  $ " + appName + " edtf-server-config xtemp-translator xtemp-script initial-events" + lineSeparator + lineSeparator);
        usage.append(" Where:" + lineSeparator);
        usage.append("  edtf-server-config:  " + appName + " configuration file (i.e. edtf.server.config.xml)." + lineSeparator);
        usage.append("  xtemp-translator:    The XTemp translator filename. For common usage xtemp_translator.xsl can be used." + lineSeparator);
        usage.append("  xtemp-script:        Your XTemp script filename." + lineSeparator);
        usage.append("  initial-events:      Your initial events filename, which should include <event> elements. If none, use noevents.xml. " + lineSeparator);
        usage.append("                       Note: functionality tested only when using noevents.xml. The full functionality is going to be implemented/tested in a future release." + lineSeparator);
        usage.append(lineSeparator);
        usage.append(" Example:" + lineSeparator);
        usage.append("  " + appName + " edtf.server.config.xml xtemp_translator.xsl myscript.xtemp noevents.xml" + lineSeparator);
        usage.append("---------------------------------------" + lineSeparator);
        System.err.println(usage.toString());
    }

    private static void configureLogger(Logger logger, Configuration config) throws Exception {
        // Configure logger level
        logger.setLevel(Level.parse(config.getProperty("logger.level").toUpperCase()));

        // Configure logger handler and formatter
        if (config.getProperty("logger.handler").compareToIgnoreCase("file-and-console") == 0
                || config.getProperty("logger.handler").compareToIgnoreCase("file") == 0) {
            FileHandler fileHandler = new FileHandler(config.getProperty("logger.filename"));

            if (config.getProperty("logger.formatter").compareToIgnoreCase("xml") == 0) {
                XMLFormatter xmlFormatter = new XMLFormatter();
                fileHandler.setFormatter(xmlFormatter);
            } else {
                SimpleFormatter txtFormatter = new SimpleFormatter();
                fileHandler.setFormatter(txtFormatter);
                logger.addHandler(fileHandler);
            }

            logger.addHandler(fileHandler);

            if (config.getProperty("logger.handler").compareToIgnoreCase("file") == 0) {
                // disable console logger
                LogManager.getLogManager().reset();
                Logger globalLogger = Logger.getLogger(java.util.logging.Logger.GLOBAL_LOGGER_NAME);
                globalLogger.setLevel(java.util.logging.Level.OFF);
            }
        }
        
        // disable jaxws related info messages. todo: move these settings to the config file.
        Logger.getLogger("javax.enterprise.resource.webservices.jaxws.server").setLevel(Level.WARNING);
    }
}
